package com.spzx.cart.service.impl;

import com.spzx.cart.api.domain.CartInfo;
import com.spzx.cart.service.ICartService;
import com.spzx.common.core.constant.SecurityConstants;
import com.spzx.common.core.context.SecurityContextHolder;
import com.spzx.common.core.domain.R;
import com.spzx.common.core.exception.ServiceException;
import com.spzx.product.api.RemoteProductService;
import com.spzx.product.api.domain.ProductSku;
import com.spzx.product.api.domain.vo.SkuPrice;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.RequestHeader;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
@Slf4j
public class CartServiceImpl implements ICartService {

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private RemoteProductService remoteProductService;

    /**
     * 添加购物车
     *
     * @param skuId  商品skuId
     * @param skuNum 商品的增量
     */
    @Override
    public void addToCart(Long skuId, Integer skuNum) {
        //1、获取当前用户的id
        Long userId = SecurityContextHolder.getUserId();//从当前线程上获取共享数据。HeaderInterceptor拦截器获取请求头信息，将数据绑定到当前线程上。
        //2、构建”用户“购物车hash结构key
        String cartKey = getCartKey(userId);
        //3、创建hash的key，以skuId作为hash的key
        String hashKey = String.valueOf(skuId);
        BoundHashOperations<String, String, CartInfo> boundHashOperations = redisTemplate.boundHashOps(cartKey);
        int maxSkuNum = 99;
        //4、判断用户购物车中是否包含该商品 如果包含：数量进行累加（某件商品数量上限99） 不包含：新增购物车商品
        if (boundHashOperations.hasKey(hashKey)) {//之前添加过这个商品到购物车，修改购物车中的数量
            //4.1、说明该商品在购物车中已有，对数量进行累加，不能超过指定上线99
            //获取缓存中的value，即CartInfo
            CartInfo cartInfo = boundHashOperations.get(hashKey);
            //查询购物车中原来的商品数量
            //购物车中单个商品数量
            int newSkuNum = cartInfo.getSkuNum() + skuNum;
            cartInfo.setSkuNum(Math.min(newSkuNum, maxSkuNum));
            cartInfo.setUpdateTime(new Date());
            boundHashOperations.put(hashKey, cartInfo);
        } else {//首次添加商品到购物车
            //4.2说明购物车没有该商品，构建购物车对象，存入Redis
            //4.3判断购物车商品种类（不同SKU）总数大于50件
            Long size = boundHashOperations.size();
            if (++size > 50) {
                throw new ServiceException("购物车商品数不要超过50件！！！");
            }
            CartInfo cartInfo = new CartInfo();
            cartInfo.setUserId(userId);
            cartInfo.setSkuId(skuId);
            cartInfo.setSkuNum(skuNum);
            //4.4.远程调用商品服务获取商品sku基本信息
            R<ProductSku> productSkuResult = remoteProductService.getProductSku(skuId, SecurityConstants.INNER);
            if (productSkuResult.getCode() == R.FAIL) {
                throw new ServiceException(productSkuResult.getMsg());
            }
            ProductSku productSku = productSkuResult.getData();
            cartInfo.setCartPrice(productSku.getSalePrice());
            cartInfo.setSkuPrice(productSku.getSalePrice());
            cartInfo.setThumbImg(productSku.getThumbImg());
            cartInfo.setSkuName(productSku.getSkuName());
            cartInfo.setIsChecked(1);
            cartInfo.setUpdateTime(new Date());
            //4.6.将购物车商品存入Redis
            boundHashOperations.put(hashKey, cartInfo);
        }
    }

    /**
     * 购物车的key
     *
     * @param userId
     * @return
     */
    private String getCartKey(Long userId) {
        String cartKey = "user:cart:" + userId;
        return cartKey;
    }

    /**
     * 购物车列表查询
     *
     * @return
     */
    @Override
    public List<CartInfo> getCartList() {
        //1.从redis中获取加在购物车中的商品
        Long userId = SecurityContextHolder.getUserId();
        String cartKey = getCartKey(userId);
        BoundHashOperations<String, String, CartInfo> boundHashOperations = redisTemplate.boundHashOps(cartKey);
        List<CartInfo> cartInfoList = boundHashOperations.values();
        if (CollectionUtils.isEmpty(cartInfoList)) {
            return new ArrayList<>();
        }
        //2.购物车列表排序，根据添加时间进行倒序排序
        cartInfoList.stream().sorted((o1, o2) ->
                o2.getCreateTime().compareTo(o1.getCreateTime())
        ).toList();
        //3.远程获取商品最新价格，给与页面价格变动提示
        List<Long> skuIdList = cartInfoList.stream().map(CartInfo::getSkuId).toList();
        R<List<SkuPrice>> skuPriceListResult = remoteProductService.getSkuPriceList(skuIdList, SecurityConstants.INNER);
        if (skuPriceListResult.getCode() == R.FAIL) {
            throw new ServiceException(skuPriceListResult.getMsg());
        }
        List<SkuPrice> skuPriceList = skuPriceListResult.getData();//最新的价格
        //List<SkuPrice> 转 Map<SkuId,skuPrice>
        Map<Long, BigDecimal> skuIdToSalePriceMap = skuPriceList.stream().collect(Collectors.toMap(SkuPrice::getSkuId, SkuPrice::getSalePrice));
        //4.更新商品最新价格：更新内存中商品最新价格，而不是购物车中的价格，因为没有重新放回到购物车。
        for (CartInfo cartInfo : cartInfoList) {
            //cartInfoList是内存中的购物车列表 把内存中的售价设置为 通过远程调用查询到数据库的购物车售价的数据列表
            cartInfo.setCartPrice(skuIdToSalePriceMap.get(cartInfo.getSkuId()));
        }
        return cartInfoList;
    }

    /**
     * 删除购物车
     *
     * @param skuId
     */
    @Override
    public void deleteCart(Long skuId) {
        //从redis缓存中获取购物车的数据，根据hash的key，删除对应的商品
        Long userId = SecurityContextHolder.getUserId();
        String cartKey = getCartKey(userId);
        //存的是hash表结构数据
        BoundHashOperations<String, String, CartInfo> boundHashOperations = redisTemplate.boundHashOps(cartKey);
        //skuId是hash的key，根据skuId直接删除
        boundHashOperations.delete(String.valueOf(skuId));
    }

    /**
     * 更新商品选中状态
     *
     * @param skuId
     * @param isChecked
     */
    @Override
    public void checkCart(Long skuId, Integer isChecked) {
        //从redis中获取hash购物车k-v信息
        Long userId = SecurityContextHolder.getUserId();
        String cartKey = getCartKey(userId);
        BoundHashOperations<String, String, CartInfo> boundHashOperations = redisTemplate.boundHashOps(cartKey);
        //把skuId转换为string类型
        String hashKey = String.valueOf(skuId);
        //校验是否有skuId
        if (boundHashOperations.hasKey(hashKey)) {
            //从hash中获取购物车商品v的信息
            CartInfo cartInfo = boundHashOperations.get(hashKey);
            //修改商品的状态
            cartInfo.setIsChecked(isChecked);
            boundHashOperations.put(hashKey, cartInfo);
        }
    }

    /**
     * 更新购物车商品全部选中状态
     *
     * @param isChecked
     */
    @Override
    public void allCheckCart(Integer isChecked) {
        //从redis中获取hash购物车k-v信息
        Long userId = SecurityContextHolder.getUserId();
        String cartKey = getCartKey(userId);
        BoundHashOperations<String, String, CartInfo> boundHashOperations = redisTemplate.boundHashOps(cartKey);
        //从hash中获取购物车商品v的信息
        List<CartInfo> cartInfoList = boundHashOperations.values();
        if (!CollectionUtils.isEmpty(cartInfoList)) {
            for (CartInfo cartInfo : cartInfoList) {
                //修改商品的状态
                cartInfo.setIsChecked(isChecked);
                boundHashOperations.put(String.valueOf(cartInfo.getSkuId()), cartInfo);
            }
        }
    }

    /**
     * 清空购物车
     */
    @Override
    public void clearCart() {
        //从redis中获取全部的购物车商品信息
        Long userId = SecurityContextHolder.getUserId();
        String cartKey = getCartKey(userId);
        //删除缓存
        redisTemplate.delete(cartKey);
    }
}